package hyl.ext.base;

import java.io.Serializable;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;

import com.alibaba.fastjson2.JSON;

import hyl.core.MyFun;
import hyl.core.info.Content;

/**
 * 一个ip 对应多个个token 一个token 只有一个ip
 * 
 * @author 37798955@qq.com
 *
 * @param <T>
 */
public class ASession<T> implements Serializable {
	/**
	 * 
	 */
// protected static Map<String,String> _usersess = new ConcurrentHashMap<>();
	private static final long serialVersionUID = 1L;
	// 错误次数
	AtomicInteger errTimes = new AtomicInteger(0);
	// 上一次登录时间戳
	Long lastStamp = MyFun.getMs();
	// 上一次异常时间戳
	Long errStamp = MyFun.getMs();
	// ip地址
	String ip;
	// 用户唯一编号,有则有效,无则无效
	T userId = null;
	/**
	 * 组织id
	 */
	Integer orgid = 0;
	/**
	 * 部门id
	 */
	Integer deptid = 0;
	// 用户登录名
	String uname;
	String 头像;// headurl
	String 别名;// alias
	// 用户登录账号
	String phone;
	String mail;
	// 登录令牌 用uuid 赋值
	String token;
	// 角色
	Integer roleid;
	// 推荐人
	T tjrid;
	// 语言种类
	int Lang = 0; // 0 英文,1 中文
	/**
	 * 自定义会话中有两个 状态 分别是字符串状态 和 整型状态
	 * 
	 * 其中字符串状态 是必须有的状态 (可以不创建该字段 ,只在内存中存在)
	 * 
	 * 而整型状态 是扩展的状态 是为了更快的比较状态 (可以不创建该字段 ,只在内存中存在)
	 */
	// 字符型状态位 必须要有
	public char[] state = { '0', '0', '0', '0', '0', '0', '0', '0' };
	// 整型状态位 扩展的状态位
	public int istate = 0;
	/**
	 * 状态 位0:表示是否登录, 0 未登录,1登录 位2:表示commitid处理状态 ,0未分配,1已分配未处理,2正在处理,处理完成,重置为0
	 * 并删除commitid
	 */
	public String icode;
	public String mcode;
	/*
	 * 该属性适用于 单点登录系统 单点系统不保留第三方应用的任何信息,
	 * 
	 * 只是保存账号openid k=appid, v=openid
	 */
	// public HashMap<String, String> bopens = new HashMap<>();
	public HashMap<String, Object> tag = new HashMap<>();
	public Content msg = new Content();

	/**
	 * 创建session 必须有ip
	 * 
	 * 
	 * @param ipaddr 只能是ip(不能含端口)
	 */
	public ASession(String ipaddr) {
		token = MyFun.getUUID();
		ip = ipaddr;
	}

	/**
	 * 从数据库反序列化出来的session,必须用 无参数
	 */
	public ASession() {
	}

	public Long getErrStamp() {
		return errStamp;
	}

	public void setErrStamp(Long errStamp) {
		this.errStamp = errStamp;
	}

	public int getErrTimes() {
		return errTimes.get();
	}

	public void setErrTimes(int errTimes) {
		this.errTimes.set(errTimes);
		;
	}

	public Long getLastStamp() {
		return lastStamp;
	}

	public void setLastStamp(Long lastStamp) {
		this.lastStamp = lastStamp;
	}

	public Integer getRoleid() {
		return roleid;
	}

	public void setRoleid(Integer roleid) {
		this.roleid = roleid;
	}

	public int getLang() {
		return Lang;
	}

	public void setLang(int lang) {
		Lang = lang;
	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public boolean eqIP(String ip2) {
		return (ip2 != null && !ip2.equals(this.ip));
	}

	public String get别名() {
		return 别名;
	}

	public void set别名(String 别名) {
		this.别名 = 别名;
	}

	public String get头像() {
		return 头像;
	}

	public void set头像(String 头像) {
		this.头像 = 头像;
	}

	public T getUserId() {
		return userId;
	}

	public String userIdToStr() {
		return String.valueOf(userId);
	}

	public void setUserId(T userId) {
		this.userId = userId;
	}

	public T getTjrid() {
		return tjrid;
	}

	public void setTjrid(T tjrid) {
		this.tjrid = tjrid;
	}

	public String getUname() {
		return uname;
	}

	public void setUname(String uname) {
		this.uname = uname;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getMail() {
		return mail;
	}

	public void setMail(String mail) {
		this.mail = mail;
	}

	/**
	 * 登录令牌 同 uuid
	 * 
	 * 这是30分钟会话型令牌 不同与ExtokenFactory 的一次性过期令牌
	 * 
	 * @return
	 */
	public String getTokenId() {
		return token;
	}

	public void setTokenId(String tokenId) {
		this.token = tokenId;
	}

	public char[] getState() {
		return state;
	}

	public void setState(char[] state) {
		this.state = state;
	}

	public void setState(int 位置, char 状态) {
		this.state[位置] = 状态;
	}

	public int getIstate() {
		return istate;
	}

	public void setIstate(int istate) {
		this.istate = istate;
	}

	public String getIcode() {
		return icode;
	}

	public void setIcode(String icode) {
		this.icode = icode;
	}

	public String getMcode() {
		return mcode;
	}

	public void setMcode(String mcode) {
		this.mcode = mcode;
	}

//	public String takeBopen(String appid) {
//		return bopens.get(appid);
//	}
//
//	public void putBopen(String appid, String openid) {
//		bopens.put(appid, openid);
//	}
//
//	public HashMap<String, String> getBopens() {
//		return bopens;
//	}
//
//	public void setBopens(HashMap<String, String> appopens) {
//		this.bopens = appopens;
//	}

	public HashMap<String, Object> getTag() {
		return tag;
	}

	public void setTag(HashMap<String, Object> tag) {
		this.tag = tag;
	}

	public Content getMsg() {
		return msg;
	}

	public void setMsg(Content msg) {
		this.msg = msg;
	}

	public void setErrTimes(AtomicInteger errTimes) {
		this.errTimes = errTimes;
	}

	// 标记异常token
	public void stop() {
		errTimes.set(9);
		errStamp = MyFun.getMs();// 更新时间戳
	}

//设置组织机构
	public Integer getOrgid() {
		return orgid;
	}

	public void setOrgid(Integer orgid) {
		this.orgid = orgid;
	}

//设置部门
	public Integer getDeptid() {
		return deptid;
	}

	public void setDeptid(Integer deptid) {
		this.deptid = deptid;
	}

	/**
	 * 重置session
	 */
	public void reset() {
		this.userId = null;
		this.uname = null;
		this.icode = null;
		this.ip = null;
		this.phone = null;
		this.mail = null;
		this.mcode = null;
		this.msg = null;
		this.头像 = null;
		this.roleid = 0;
		this.tjrid = null;
		this.别名 = null;
		this.orgid = 0;
		this.state[0] = '0';
		this.state[1] = '0';
		this.istate = 0;
		start();
	}

	/**
	 * 登录成功了 , 重启会话
	 */
	public void start() {
		errTimes.set(0);
		// errStamp = MyFun.getMs();// 更新时间戳
		lastStamp = MyFun.getMs(); // 登录成功了 过期时间归零
		this.state[1] = REQ_无任务;
	}

	// 如果访问错误次数大于4 ,且等待时间超过30分钟,重置错误次数和上次登录时间
	/**
	 * 
	 * @return
	 */
	public synchronized boolean incError() {
		long ms = MyFun.getMs();
		if (errTimes.get() > SessionFactory.MaxErrTimes) {
			if (ms > (errStamp + SessionFactory.EXPIRED30m)) {
				errTimes.set(0);
				errStamp = ms;
				return true;
			}
			return false;
		} else {
			errTimes.incrementAndGet();
			errStamp = ms;
			return true;
		}
	}

	// 更新时间戳:每次登录时,在过滤器中可以调用这个更新,如果超时了,就不更新了
	/**
	 * 如果超时返回true 如果没有过期 返回 false <br>
	 * 
	 * 调用时更新时间戳
	 */
	public synchronized boolean is过期() {
		long ms = MyFun.getMs();
		if ((ms - lastStamp) < SessionFactory.EFFECTTIMES) {
			lastStamp = ms;// 更新时间戳
			return false;
		} else {
			return true;
		}
	}

	public void refresh任务状态() {
		this.state[1] = REQ_无任务;
	}

	public static final char REQ_无任务 = '0';
	public static final char REQ_受理中 = '1';
	public static final char REQ_已处理 = '2';
	public static final char REQ_异常 = '9';

	public void smsCode() {
	}

	public String toJsonString() {
		return JSON.toJSONString(this);
	}
}